package export

import (
	"bufio"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"game/game-design/loader"
	"game/game-design/util"
	"io"
	"os"
	"sort"
	"strings"
)

func Export(args []string) {
	exportArgs := NewExportArgs(args)

	fileList := util.GetNameAndPathInDir(exportArgs.SourceHome)
	//排序文件名
	sort.Slice(fileList, func(i, j int) bool { return fileList[i].Name() < fileList[j].Name() })

	var readerIO IDesignIO = exportArgs.Reader

	var md5Map map[string]string
	if exportArgs.Mode == "fast" {
		md5Map = *readMd5(exportArgs.ModeFile)
		fmt.Println("使用快速模式导出")
	} else {
		md5Map = make(map[string]string, 100)
		fmt.Println("使用完整模式导出")

		for _, exportArgs := range exportArgs.Exportfor {
			outputFolder := exportArgs[2]
			os.RemoveAll(outputFolder)
		}
	}
	//检查类名是否重复
	classNameChecker := make(map[string]string)

	if exportArgs.NeedFilterFiles {
		fmt.Println("将进行个别导出")
	} else {
		fmt.Println("将进行默认导出")
	}
	for _, file := range fileList {
		if strings.HasPrefix(file.Name(), "~$") {
			continue
		}
		if exportArgs.NeedFilterFiles {
			parts := strings.Split(file.Name(), ".")
			_, exist := exportArgs.DealFiles[parts[0]]
			if !exist {
				continue
			}
		} else {
			if exportArgs.Mode == "fast" {
				md5, ok := md5Map[file.Name()]
				if ok {
					currMd5, ok := fileMd5(file.Url())
					if ok {
						if md5 == currMd5 {
							fmt.Println("文件未发生变化\t" + file.Name())
							continue
						} else {
							md5Map[file.Name()] = currMd5
						}
					}
				} else {
					currMd5, ok := fileMd5(file.Url())
					if ok {
						md5Map[file.Name()] = currMd5
					}
				}
			}
		}

		fileFullPath := file.Url()
		designFiles, err := readerIO.Read(fileFullPath, exportArgs.DesignDefine)
		if err != nil {
			fmt.Println("读取文件", file.Name(), "发生错误", err)
			continue
		}
		//导出除语言表外的配置
		for _, dFile := range designFiles {
			if dFile.ClassName == exportArgs.LanguageClass {
				continue
			}
			duplicateFile, duplicate := classNameChecker[dFile.ClassName]
			if duplicate {
				panic(fmt.Sprintf("\033[31m[ERROR]\033[0m%s文件中的#name定义%s与%s文件中的#name定义重复", dFile.Name, dFile.ClassName, duplicateFile))
			}
			classNameChecker[dFile.ClassName] = dFile.Name

			//1、收集语言字段相关信息
			CollectLanguage(dFile)
			//2、处理语言字段加工
			newDFile := HandleLanguage(dFile)

			for _, exportArgs := range exportArgs.Exportfor {
				exportType := exportArgs[0]
				outputType := exportArgs[1]
				outputFolder := exportArgs[2]

				newDFile.OutputNameType = exportArgs[3]

				var writerIO IDesignIO = GetDesignIO(outputType)
				writerIO.Write(newDFile, outputFolder, exportType)
			}
		}
	}
	//导出语言表配置
	var langFile *loader.DesignFile = GenLanguageFile(readerIO, exportArgs)
	if langFile != nil {
		for _, exportArgs := range exportArgs.Exportfor {
			exportType := exportArgs[0]
			outputType := exportArgs[1]
			outputFolder := exportArgs[2]

			langFile.OutputNameType = exportArgs[3]

			var writerIO IDesignIO = GetDesignIO(outputType)
			writerIO.Write(langFile, outputFolder, exportType)
		}
	}

	if exportArgs.Mode == "fast" {
		writeMd5(exportArgs.ModeFile, md5Map)
	}
}

// 生成文件的MD5
func fileMd5(filePath string) (string, bool) {
	file, err := os.Open(filePath)
	if err != nil {
		return "", false
	}
	defer file.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, file); err != nil {
		return "", false
	}

	return hex.EncodeToString(hash.Sum(nil)), true
}

// 读取MD5文件
func readMd5(md5File string) *map[string]string {
	md5Map := make(map[string]string, 100)
	file0, err := os.Open(md5File)
	if err != nil {
		return &md5Map
	}
	scanner := bufio.NewScanner(file0)
	for scanner.Scan() {
		line := scanner.Text()
		parts := strings.Split(line, "=")
		if len(parts) >= 2 {
			md5Map[parts[0]] = parts[1]
		}
	}
	return &md5Map
}

// 写入MD5文件
func writeMd5(md5File string, md5Map map[string]string) {
	keyArray := make([]string, 0, len(md5Map))
	for key := range md5Map {
		keyArray = append(keyArray, key)
	}
	sort.Strings(keyArray)

	file, err := os.OpenFile(md5File, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()

	for _, key := range keyArray {
		md5Value := md5Map[key]
		file.WriteString(string(fmt.Sprintf("\n%s=%s", key, md5Value)))
	}
}
